import QtQuick 2.0
import QtQuick.Controls 2.15
import FileIO 1.0

Item {
    property string gameVersion
    property string gamePath

    signal patchReverted()
    signal errorRevertingPatch()

    signal patchApplied()
    signal errorApplyingPatch()

    signal patchCanceled()

    Script {
        id: script

        workingDirectory: gamePath

        readonly property int modeRevert: 0
        readonly property int modeCheck: 1
        readonly property int modeConfirmTos: 2
        readonly property int modeBlock: 3
        readonly property int modeApply: 4
        readonly property int modeConfirmUntested: 5
        property int mode: modeRevert

        onFinished: {
            console.log(`WinePatcher Script finished with code: ${code}`)

            switch (mode) {
                case modeCheck:
                    onCheckFinished(code, output)
                    break

                case modeRevert:
                    ui.log(output)
                    onRevertFinished(code)
                    break

                case modeApply:
                    ui.log(output)
                    onApplyFinished(code)
                    break
            }
        }


        function execPatcher(command) {
            execScript("patcher-wrapper", [gameVersion, command])
        }

        function onCheckFinished(code, output) {
            switch (code) {
            case 0:
                applyPatch()
                break

            case 42:
                confirmBlocking()
                break

            default:
                ui.log("")
                ui.log(output)
                ui.log(qsTr("Error while applying patch"))
                errorApplyingPatch()
                break
            }

        }

        function onRevertFinished(code) {
            if (code === 0) {
                patchReverted()
            } else {
                errorRevertingPatch()
            }
        }

        function onApplyFinished(code) {
            switch (code) {
            case 0:
                patchApplied()
                break

            case 1:
                checkUntested(output)
                break

            default:
                errorApplyingPatch()
            }
        }

        // ---------------------------------------------------------------------

        function confirmTos() {
            mode = modeConfirmTos
            textDialog.text = qsTr("By using the patch you are violating the game's Terms of Service!")
                            + "\n" + qsTr("Do you accept the risk and possible consequences?")
            dialogConfirm.open()
        }

        function checkPatch() {
            mode = modeCheck
            execPatcher("check")
        }

        function checkUntested(output) {
            if (output.indexOf("UNTESTED PATCH") === -1) {
                errorApplyingPatch()
                return
            }

            mode = modeConfirmUntested
            textDialog.text = output.replace(/^Starting.*$/mg, "").trim().
                replace(/===/g, "").replace(/^[ ]*/mg, "").replace(/[ ]*$/mg, "").
                replace(/^.*to test this patch.*$/mg, qsTr("Proceed with installing the patch?"))
            dialogConfirm.open()
        }

        function confirmBlocking() {
            let servers = output.replace(/\n/g, "|")
                    .replace(/.*SERVERS_BEGIN(.*)SERVERS_END.*/g, "$1")
                    .replace(/\|/g, "\n")
            textDialog.text = qsTr("To make game work, the modification of /etc/hosts is required.") + "\n"
                    + qsTr("If you choose 'No' you must to add the servers manually.") + "\n"
                    + qsTr("For details see original Dawn project.") + "\n"
                    + qsTr("Do you wish to add the following servers to /etc/hosts?") + "\n\n"
                    + servers.trim()

            dialogConfirm.open()
        }

        function applyPatch() {
            mode = modeApply
            execPatcher("patch")
        }

        function applyUntestedPatch() {
            mode = modeApply
            execPatcher("patch-untested")
        }

        function applyBlockAndPatch() {
            mode = modeBlock
            execPatcher("block")
        }
    }


    Dialog {
        id: dialogConfirm
        anchors.centerIn: parent
        title: window.title
        standardButtons: Dialog.Yes | Dialog.No
        closePolicy: Popup.NoAutoClose
        modal: true
        focus: true

        Flickable {
            id: flickable
            anchors.fill: parent
            implicitHeight: textDialog.height
            implicitWidth: block * 10

            boundsBehavior: Flickable.DragAndOvershootBounds
            flickableDirection: Flickable.VerticalFlick

            ScrollBar.vertical: ScrollBar {
                id: flickScroll
            }

            TextArea.flickable: TextArea {
                id: textDialog
                width: parent.width
                height: parent.height
                readOnly: true
                wrapMode: TextArea.Wrap
                persistentSelection: true
                topPadding: 0
                bottomPadding: 0
                selectByMouse: true
                color: "black"
            }
        }

        onAccepted: {
            switch (script.mode) {
            case script.modeConfirmTos:
                script.checkPatch()
                break
            case script.modeCheck:
                script.applyBlockAndPatch()
                break
            case script.modeConfirmUntested:
                script.applyUntestedPatch()
                break
            default:
                ui.log("unexpected mode " + script.mode)
                installError()
                break
            }
        }

        onRejected: {
            switch (script.mode) {
            case script.modeConfirmTos:
            case script.modeCheck:
                patchCanceled()
                break
            default:
                ui.log("unexpected mode " + script.mode)
                installError()
                break
            }
        }
    }


    function applyPatch() {
        script.confirmTos()
    }

    function revertPatch() {
        if (!isPatchInstalled()) {
            ui.log(qsTr("Wine patch is not installed."))
            patchReverted()
            return
        }

        ui.log("")
        ui.log(qsTr("Reverting Wine patch..."))
        script.mode = script.modeRevert
        script.workingDirectory = settings.gamePath
        script.execPatcher("revert")
    }

    function isPatchInstalled() {
        return FileIO.isFileExists(settings.gamePath + '/launcher.bat')
    }
}
